package com.qfoud.edu.shiro.framwork.slot.impl;

import com.qfoud.edu.shiro.framwork.exception.ShiroException;
import com.qfoud.edu.shiro.framwork.pojo.Context;
import com.qfoud.edu.shiro.framwork.slot.base.BaseSlot;
import com.qfoud.edu.shiro.framwork.utils.StringUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;

/**
 * @author xiaobobo
 * @title: MethodAuthorizeSlot
 * @projectName cd-java-2303-project-parent
 * @description: 这个执行到最后一个位置的方法级别的这样一个过滤器
 * 这个过滤器的作用是判断用户是否具有访问某一个方法 权限
 * @date 2023/5/16  14:28
 */
public class MethodAuthorizeSlot implements BaseSlot {

    //登陆页面
    private String loginPage;

    //登陆的Url地址
    private String loginUrl;

    //没有权限访问的时候访问的页面
    private String unAuthPage;

    public MethodAuthorizeSlot(String loginPage,String loginUrl,String unAuthPage){
         this.loginPage=loginPage;
         this.loginUrl=loginUrl;
         this.unAuthPage=unAuthPage;
    }

    @Override
    public void dealRequestAndResponse(ServletRequest request, ServletResponse response) throws IOException {
        //首先就要获取请求地址
        HttpServletRequest req= (HttpServletRequest) request;
        //接下来获取请求地址
        String requestURI = req.getRequestURI();
        //判断是不是登陆
        if(StringUtils.equals(requestURI,loginPage)||StringUtils.equals(requestURI,loginUrl)){
          //说明是登陆
            return;
        }
        //执行到这里说明这个方法需要判断是否需要权限或者角色才能访问
        List<String> stringList = Context.getRolesAndPerms().get(requestURI);
        if(null==stringList||stringList.size()==0){
            //说明当前的请求地址不需要权限 和 角色就能访问
            //放行
            return;
        }
        //程序执行到这里 说明当前的方法需要权限或者角色才能访问
        // stringList中包含的就是需要的权限 或者 角色
        //接下来获取用户具有的权限或者角色?
        //获取Session对象
        HttpSession session = req.getSession();
        List<String> perms = (List<String>) session.getAttribute("perms");
        List<String> roles = (List<String>) session.getAttribute("roles");
        //接下来就要判断用户是否有这个方法上需要的权限或者角色了
        if(!checkRolesAndPerms(stringList,perms,roles)){
            //你可以返回当前无权限
            sendResponse(req,response);
            throw new ShiroException("没有权限访问这个方法");
        }
    }

    /**
     * 这个就是没有权限访问的时候的处理器
     * @param req
     * @param response
     */
    private void sendResponse(HttpServletRequest req, ServletResponse response) throws IOException {
       //直接跳转到一个没有权限访问的时候的页面
       HttpServletResponse resp= (HttpServletResponse) response;
       resp.sendRedirect(unAuthPage);
    }

    /**
     * 判断用户是否具有指定的权限或者角色
     * @param stringList
     * @param perms
     * @param roles
     */
    private boolean checkRolesAndPerms(List<String> stringList, List<String> perms, List<String> roles) {
         //先进行处理将perms中的值和roles中的值拧到一个集合中去
        for (int i = 0; i < roles.size(); i++) {
            perms.add("ROLE_"+roles.get(i));
        }
        //接下来就成了判断stringList中的元素是不是都存在于 perms集合中
        for (int i = 0; i <stringList.size() ; i++) {
            //取出方法需要的权限或者角色
            String roleAndPerm = stringList.get(i);
            //只需要判断这个值是否在perms这个集合中
            boolean contains = perms.contains(roleAndPerm);
            if(!contains){
               return false;
            }
        }
        return true;
    }
}
